using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Net;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Middleware
{
    /// <summary>
    /// 速率限制中间件 - 防止API滥用和DDoS攻击
    /// </summary>
    public class RateLimitingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<RateLimitingMiddleware> _logger;
        private readonly IMemoryCache _cache;
        private readonly RateLimitOptions _options;
        
        // 用于存储客户端请求计数
        private static readonly ConcurrentDictionary<string, ClientRequestInfo> _clientRequests = new();

        public RateLimitingMiddleware(
            RequestDelegate next, 
            ILogger<RateLimitingMiddleware> logger,
            IMemoryCache cache,
            RateLimitOptions? options = null)
        {
            _next = next;
            _logger = logger;
            _cache = cache;
            _options = options ?? new RateLimitOptions();
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // 跳过速率限制的路径
            if (ShouldSkipRateLimit(context.Request.Path))
            {
                await _next(context);
                return;
            }

            // 获取客户端标识
            var clientId = GetClientIdentifier(context);
            
            // 检查速率限制
            var rateLimitResult = await CheckRateLimitAsync(clientId, context.Request.Path);
            
            if (rateLimitResult.IsBlocked)
            {
                await HandleRateLimitExceededAsync(context, rateLimitResult);
                return;
            }

            // 添加速率限制头信息
            AddRateLimitHeaders(context.Response, rateLimitResult);

            await _next(context);
        }

        private Task<RateLimitResult> CheckRateLimitAsync(string clientId, PathString path)
        {
            var now = DateTime.UtcNow;
            var windowStart = now.Subtract(_options.WindowSize);
            
            // 获取或创建客户端请求信息
            var clientInfo = _clientRequests.AddOrUpdate(clientId, 
                new ClientRequestInfo { FirstRequestTime = now },
                (key, existingInfo) => existingInfo);

            lock (clientInfo)
            {
                // 清理过期的请求记录
                clientInfo.Requests.RemoveAll(r => r < windowStart);
                
                // 检查是否超过限制
                var currentRequests = clientInfo.Requests.Count;
                var limit = GetRateLimit(path);
                
                if (currentRequests >= limit)
                {
                    _logger.LogWarning("Rate limit exceeded for client {ClientId}. Current: {Current}, Limit: {Limit}", 
                        clientId, currentRequests, limit);
                        
                    var blocked = new RateLimitResult
                    {
                        IsBlocked = true,
                        CurrentRequests = currentRequests,
                        Limit = limit,
                        ResetTime = windowStart.Add(_options.WindowSize),
                        RetryAfter = _options.WindowSize
                    };
                    return Task.FromResult(blocked);
                }
                
                // 记录当前请求
                clientInfo.Requests.Add(now);
                
                var allowed = new RateLimitResult
                {
                    IsBlocked = false,
                    CurrentRequests = currentRequests + 1,
                    Limit = limit,
                    ResetTime = windowStart.Add(_options.WindowSize),
                    RetryAfter = TimeSpan.Zero
                };
                return Task.FromResult(allowed);
            }
        }

        private string GetClientIdentifier(HttpContext context)
        {
            // 优先使用认证用户ID
            var userId = context.User?.Identity?.Name;
            if (!string.IsNullOrEmpty(userId))
            {
                return $"user:{userId}";
            }

            // 使用IP地址
            var ipAddress = GetClientIpAddress(context);
            return $"ip:{ipAddress}";
        }

        private string GetClientIpAddress(HttpContext context)
        {
            // 检查代理头
            var forwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (!string.IsNullOrEmpty(forwardedFor))
            {
                return forwardedFor.Split(',')[0].Trim();
            }

            var realIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(realIp))
            {
                return realIp;
            }

            return context.Connection.RemoteIpAddress?.ToString() ?? "unknown";
        }

        private int GetRateLimit(PathString path)
        {
            var pathValue = path.Value?.ToLower();
            
            // API特定限制
            if (pathValue?.StartsWith("/api/auth/") == true)
            {
                return _options.AuthEndpointLimit; // 认证接口更严格
            }
            
            if (pathValue?.StartsWith("/api/upload/") == true)
            {
                return _options.UploadEndpointLimit; // 上传接口限制
            }
            
            if (pathValue?.StartsWith("/api/search/") == true)
            {
                return _options.SearchEndpointLimit; // 搜索接口限制
            }

            return _options.DefaultLimit;
        }

        private static bool ShouldSkipRateLimit(PathString path)
        {
            var skipPaths = new[]
            {
                "/health",
                "/swagger",
                "/favicon.ico",
                "/_next/static/",
                "/static/"
            };

            return skipPaths.Any(skipPath => 
                path.Value?.StartsWith(skipPath, StringComparison.OrdinalIgnoreCase) == true);
        }

        private void AddRateLimitHeaders(HttpResponse response, RateLimitResult result)
        {
            response.Headers["X-RateLimit-Limit"] = result.Limit.ToString();
            response.Headers["X-RateLimit-Remaining"] = Math.Max(0, result.Limit - result.CurrentRequests).ToString();
            response.Headers["X-RateLimit-Reset"] = new DateTimeOffset(result.ResetTime).ToUnixTimeSeconds().ToString();
            
            if (result.IsBlocked)
            {
                response.Headers["Retry-After"] = ((int)result.RetryAfter.TotalSeconds).ToString();
            }
        }

        private async Task HandleRateLimitExceededAsync(HttpContext context, RateLimitResult result)
        {
            context.Response.StatusCode = 429; // Too Many Requests
            context.Response.ContentType = "application/json";

            var response = new
            {
                error = "Too Many Requests",
                message = "Rate limit exceeded. Please try again later.",
                limit = result.Limit,
                retryAfter = (int)result.RetryAfter.TotalSeconds,
                resetTime = result.ResetTime,
                timestamp = DateTime.UtcNow
            };

            await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(response));
        }

        // 定期清理过期的客户端信息
        public static void CleanupExpiredClients(TimeSpan maxAge)
        {
            var cutoff = DateTime.UtcNow.Subtract(maxAge);
            var keysToRemove = _clientRequests
                .Where(kvp => kvp.Value.FirstRequestTime < cutoff)
                .Select(kvp => kvp.Key)
                .ToList();

            foreach (var key in keysToRemove)
            {
                _clientRequests.TryRemove(key, out _);
            }
        }
    }

    /// <summary>
    /// 速率限制配置选项
    /// </summary>
    public class RateLimitOptions
    {
        /// <summary>
        /// 时间窗口大小（默认1分钟）
        /// </summary>
        public TimeSpan WindowSize { get; set; } = TimeSpan.FromMinutes(1);
        
        /// <summary>
        /// 默认请求限制（每分钟）
        /// </summary>
        public int DefaultLimit { get; set; } = 100;
        
        /// <summary>
        /// 认证接口限制（每分钟）
        /// </summary>
        public int AuthEndpointLimit { get; set; } = 10;
        
        /// <summary>
        /// 上传接口限制（每分钟）
        /// </summary>
        public int UploadEndpointLimit { get; set; } = 20;
        
        /// <summary>
        /// 搜索接口限制（每分钟）
        /// </summary>
        public int SearchEndpointLimit { get; set; } = 50;
    }

    /// <summary>
    /// 速率限制结果
    /// </summary>
    public class RateLimitResult
    {
        public bool IsBlocked { get; set; }
        public int CurrentRequests { get; set; }
        public int Limit { get; set; }
        public DateTime ResetTime { get; set; }
        public TimeSpan RetryAfter { get; set; }
    }

    /// <summary>
    /// 客户端请求信息
    /// </summary>
    public class ClientRequestInfo
    {
        public DateTime FirstRequestTime { get; set; }
        public List<DateTime> Requests { get; set; } = new();
    }
}
